package org.logtime.blog.interceptor;

import java.lang.annotation.Annotation;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.logtime.blog.annotation.AccessLevel;
import org.logtime.blog.annotation.Cache;
import org.logtime.blog.exception.ApiException;
import org.logtime.blog.module.JsonModule;
import org.logtime.blog.pojo.User;
import org.logtime.blog.service.CacheService;
import org.logtime.blog.service.PersistService;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @version: 1.0
 * @Author: itmins
 * @Email: itmins@gmail.com
 */
public class ApiInterceptor implements HandlerInterceptor {

	public static final String ACCESS_USER_IP_REQUEST_NAME = "accessIp";

	public static final String ACCESS_USER_REQUEST_NAME = "accessUser";

	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Annotation accessLevelAnnotation = handlerMethod.getMethod()
				.getAnnotation(AccessLevel.class);
		long accessLevel = (null == accessLevelAnnotation) ? AccessLevel.ADMIN_LEVER
				: ((AccessLevel) accessLevelAnnotation).level();
		if (AccessLevel.VISTOR_LEVER < accessLevel) {
			User user = persistService.getUser(
					request.getParameter("access_email"),
					request.getParameter("access_password"));
			if (null == user || user.getLevel() < accessLevel) {
				long error = ApiException.USER_ACCESS_ERROR_CODE;
				if (null == user
						&& (null == persistService.get(User.class).getData() || 0 == persistService
								.get(User.class).getData().size())) {
					error = ApiException.BLOG_NOT_INIT_ERROR_CODE;
				}
				response.getWriter().write(
						JsonModule.getJson(new ApiException(error)).toString());
				return false;
			}
			String accessIp = request.getHeader("x-forwarded-for");
			if (request.getHeader("x-forwarded-for") == null) {
				accessIp = request.getRemoteAddr();
			}
			request.setAttribute(ACCESS_USER_IP_REQUEST_NAME, accessIp);
			request.setAttribute(ACCESS_USER_REQUEST_NAME, user);
		}
		Annotation cacheAnnotation = handlerMethod.getMethod().getAnnotation(
				Cache.class);
		if (null != cacheAnnotation
				&& Cache.CACHE_OPEN.equals(((Cache) cacheAnnotation).value())) {
			Object cache = cacheService.get(this.getKey(request));
			if (null != cache) {
				response.getWriter().write(cache.toString());
				return false;
			}
		}
		return true;
	}

	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handlerMethod,
			ModelAndView modelAndView) throws Exception {
		if (null != modelAndView && null != modelAndView.getModelMap()) {
			for (Object o : modelAndView.getModelMap().values()) {
				if (o instanceof JsonModule) {
					String result = o.toString();
					Annotation cacheAnnotation = ((HandlerMethod) handlerMethod)
							.getMethod().getAnnotation(Cache.class);
					if (null != cacheAnnotation) {
						if (Cache.CACHE_OPEN.equals(((Cache) cacheAnnotation)
								.value())) {
							cacheService.put(this.getKey(request), result);
						} else {
							if (Cache.CACHE_CLEAR
									.equals(((Cache) cacheAnnotation).value())) {
								cacheService.clear();
							}
						}
					}
					response.getWriter().write(result);
				}
			}
			modelAndView.clear();
		}
	}

	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse response, Object arg2, Exception e)
			throws Exception {
		if (null != e) {
			response.getWriter().write(JsonModule.getJson(e).toString());
			response.getWriter().flush();
		}
	}

	private String getKey(HttpServletRequest request) {
		String key = request.getRequestURL().toString();
		for (Object k : request.getParameterMap().keySet()) {
			String value = request.getParameter(k.toString());
			if (null != value && !"".equals(value.trim())) {
				key = key + (key.contains("?") ? "&" : "?") + k.toString()
						+ "=" + value;
			}
		}
		return key;
	}

	@Resource
	private CacheService cacheService;

	@Resource
	private PersistService persistService;

	public CacheService getCacheService() {
		return cacheService;
	}

	public void setCacheService(CacheService cacheService) {
		this.cacheService = cacheService;
	}

	public PersistService getPersistService() {
		return persistService;
	}

	public void setPersistService(PersistService persistService) {
		this.persistService = persistService;
	}
}